/**************************
* @Summary
* @Author 20009200303 赵传博
* @Date 6/7/2022
* @Note
*****************************/

#ifndef EX6_LEXER_H
#define EX6_LEXER_H
#include "common.h"
#include <map>

extern string txt;
enum Token_type{
    NAME,
    NUMBER,
    END,
    ASSIGNEND,
    PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
    PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};


class Lexer {
private:
    int i;
    char* exprText;
    Token_type curr_tok;
    double number_value;
    string buffer;
    string string_value;
    map<string, double> table;
    /**
     * 由于有些全局变量不小心放在了Lexer里，用单例模式补救
     * C++提供了关键字explicit，可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,
     * 声明为explicit的构造函数不能在隐式转换中使用。
        C++中， 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数)，
        承担了两个角色。
        1 是个构造；2 是个默认且隐含的类型转换操作符。
        所以， 有时候在我们写下如 AAA = XXX， 这样的代码，
        且恰好XXX的类型正好是AAA单参数构造器的参数类型， 这时候编译器就自动调用这个构造器，
        创建一个AAA的对象。这样看起来好象很酷，很方便。
        但在某些情况下， 却违背了程序员的本意。这时候就要在这个构造器前面加上explicit修饰，
        指定这个构造器只能被明确的调用/使用， 不能作为类型转换操作符被隐含的使用。
     */
    explicit Lexer(const char* str);
    static Lexer* lexerInstance;

public:

    static Lexer* getInstance(const char* str);

    /*
     * 得到当前的符号到底是啥类型
     *  是运算符？还是赋值？还是具体的数？还是其他的比如某一行结束或者退出？
     */
    Token_type get_token();

    //getters and setters
    Token_type getcurrentToken() { return curr_tok; }
    double getNumber_value() { return number_value; }
    string getString_value() { return string_value; }
    void setNumberValue(double numberValue);
    //在每一次解析后，将除了全局变量外的其他变量清空
    void clear();

    map<string, double> &getTable();
};


#endif //EX6_LEXER_H
